package xgit

import (
	"git-agent/utils/xlog"
	"github.com/kataras/golog"
	"gopkg.in/src-d/go-git.v4"
	"gopkg.in/src-d/go-git.v4/plumbing"
	"gopkg.in/src-d/go-git.v4/plumbing/transport/ssh"
	"os/user"
	"strings"
)

type Params struct {
	URL string
	Path string
	RefType string
	RefName string
	Action string
	Project string
}

func getPemFile() (string, error)  {
	u, err := user.Current()
	if err != nil {
		return "", err
	}
	return u.HomeDir + "/.ssh/id_rsa", nil
}

var sshAuth *ssh.PublicKeys
var logger *golog.Logger

func Setup(log * golog.Logger)  {
	setLogger(log)
	auth()
}

func auth()  {
	pem, err := getPemFile()
	if err != nil {
		panic(err)
	}

	//获取pem地址
	logger.Debug("get pem file:", pem)
	sshAuth, err = ssh.NewPublicKeysFromFile("git", pem, "");
}

func setLogger(log *golog.Logger)  {
	logger = log
}

func Clone(param *Params) (*git.Repository, error) {
	logger.Info("git clone ", param.URL)

	var referenceName plumbing.ReferenceName
	if 0 == strings.Compare(param.RefType, "branch") {
		referenceName = plumbing.NewBranchReferenceName(param.RefName)
	} else {
		referenceName = plumbing.NewTagReferenceName(param.RefName)
	}

	logger.Debug("referenceName:", referenceName)

	rep, err := git.PlainClone(param.Path, false, &git.CloneOptions{
		URL: param.URL,
		RecurseSubmodules: git.DefaultSubmoduleRecursionDepth,
		Auth: sshAuth,
		ReferenceName: referenceName,
	})

	if err != nil {
		logger.Debug(err)
		return nil, err
	}

	ref, err := rep.Head()
	if err != nil {
		logger.Debug(err)
		return nil, err
	}

	commit, err := rep.CommitObject(ref.Hash())
	if err != nil {
		logger.Debug(err)
		return nil, err
	}

	/*w, err := rep.Worktree()
	if err != nil {
		logger.Debug(err)
		return nil, err
	}

	err = w.Checkout(&git.CheckoutOptions{
		Hash: ref.Hash(),
		Branch: "develop",
	})
	if err != nil {
		logger.Debug(err)
		return nil, err
	}*/

	logger.Debug(commit)

	if err != nil {
		logger.Error(err)
		return nil, err
	}
	return rep, nil
}

func RepositoryAlreadyExists(err error) bool  {
	if err != nil && err == git.ErrRepositoryAlreadyExists {
		return true
	}
	return false;
}

func RepositoryNotExists(err error) bool  {
	if err != nil && err == git.ErrRepositoryNotExists {
		return true
	}
	return false;
}

func Pull(param *Params) (*git.Repository, error)  {
	rep, err := git.PlainOpen(param.Path)
	if err != nil {
		logger.Error(err)
		return nil, err
	}

	// Get the working directory for the repository
	w, err := rep.Worktree()
	if err != nil {
		logger.Error(err)
		return rep, err
	}

	// Pull the latest changes from the origin remote and merge into the current branch
	logger.Info("git pull origin")

	var referenceName plumbing.ReferenceName
	if 0 == strings.Compare(param.RefType, "branch") {
		referenceName = plumbing.NewBranchReferenceName(param.RefName)
	} else {
		referenceName = plumbing.NewTagReferenceName(param.RefName)
	}

	logger.Info("referenceName:", referenceName)

	if err = w.Pull(&git.PullOptions{
		RemoteName: "origin",
		Auth: sshAuth,
		//SingleBranch:true,
		//Force:true,
		ReferenceName: referenceName});
	err != nil {
		if err == git.NoErrAlreadyUpToDate {
			logger.Info(err)
			return rep, nil
		}
		if err != git.ErrNonFastForwardUpdate {
			return rep, err
		}
	}

	//checkout
	if err = w.Checkout(&git.CheckoutOptions{
		Branch: referenceName});
		err != nil {
		logger.Error(err)
		return rep, err
	}


	// Print the latest commit that was just pulled
	ref, err := rep.Head()
	xlog.Error.Println("head", ref, err)
	if err != nil {
		logger.Error(err)
		return rep, err
	}
	commit, err := rep.CommitObject(ref.Hash())
	if err != nil {
		logger.Error(err)
		return rep, err
	}

	logger.Info(commit)

	return rep, nil
}